import messageVue from './TMessage.vue'
import { createApp } from 'vue'
import { getZIndex, randomWord } from '../../utils/utils'
import type { MessageProps } from './TMessage.vue'
import type { ComponentPublicInstance } from 'vue'
import type { Emitter } from 'mitt'

// 默认消息消失时间
const MessageDuration = 2000

interface MessageInstance extends ComponentPublicInstance {
  closeMessage?: () => void
  setCurrentIndex?: (val: number) => void
  messageMitt?: Emitter<{ close: () => void }>
}

interface GlobalMessageProps extends MessageProps {
  duration: number
}

type MessageArr = { id: string; app: MessageInstance; floor: number; dom: HTMLElement }
let messageArr: MessageArr[] = []

class GlobalMessage {
  private readonly props: Partial<GlobalMessageProps>
  private messageDom: HTMLElement | undefined
  private messageApp: MessageInstance | undefined
  private messageId: string | undefined

  constructor(props: Partial<GlobalMessageProps> | string = {}) {
    if (typeof props === 'string') {
      this.props = {
        message: props,
        duration: MessageDuration
      }
    } else {
      this.props = Object.assign({ duration: MessageDuration }, props)
    }
    this.#initMessage()
  }

  #initMessage(): void {
    // 当前所有消息最后一个的楼层位置
    const currentFloor = messageArr[messageArr.length - 1]?.floor
    // 根据固定参数 判定楼层位置 当固定位置时 楼层号不变
    const floorNext =
      this.props?.isFixed === undefined
        ? currentFloor + 1 || 0
        : !this.props.isFixed
          ? currentFloor + 1 || 0
          : currentFloor || 0
    // 创建dom 并将消息dom插入body
    this.messageDom = document.createElement('div')
    this.messageDom.className = 'ttt-message-wrapper'
    this.messageDom.style.position = 'fixed'
    this.messageDom.style.zIndex = String(getZIndex())
    document.body.appendChild(this.messageDom)
    this.messageId = randomWord()
    this.messageApp = createApp(messageVue, Object.assign(this.props, { id: this.messageId })).mount(this.messageDom)
    // 在消息队列中 缓存每一条消息
    messageArr.push({
      dom: this.messageDom,
      id: this.messageId,
      app: this.messageApp,
      floor: floorNext
    })
    // 获取新增消息后 当前最新的楼层位置
    if (this.messageApp?.setCurrentIndex) this.messageApp.setCurrentIndex(floorNext)
    if (this.messageApp?.messageMitt) this.messageApp.messageMitt.on('close', this.close.bind(this))
    if (this.props.duration) setTimeout(this.close.bind(this), Math.abs(this.props.duration))
  }

  private close(): void {
    const current = messageArr.find((item: MessageArr) => item.id === this.messageId)
    messageArr.forEach((item: MessageArr): void => {
      if (current && current.floor <= item.floor) {
        if (item.floor > 0) item.floor--
      }
    })
    const currentMessage = messageArr.find((item: MessageArr) => item.id === this.messageId)
    messageArr = messageArr.filter((item: MessageArr) => item.id !== this.messageId)
    messageArr.forEach((item: MessageArr): void => {
      if (item.app.setCurrentIndex) item.app.setCurrentIndex(item.floor)
    })
    if (currentMessage?.app && currentMessage.app.closeMessage) currentMessage.app.closeMessage()
    setTimeout(() => {
      if (currentMessage?.dom) currentMessage.dom.remove()
    }, 300)
  }
}

export const TMessage = (props?: Partial<GlobalMessageProps> | string): GlobalMessage => new GlobalMessage(props)
TMessage.primary = (mes: string) => {
  TMessage({
    message: mes,
    type: 'primary'
  })
}
TMessage.success = (mes: string) => {
  TMessage({
    message: mes,
    type: 'success'
  })
}
TMessage.warning = (mes: string) => {
  TMessage({
    message: mes,
    type: 'warning'
  })
}
TMessage.error = (mes: string) => {
  TMessage({
    message: mes,
    type: 'danger'
  })
}
TMessage.default = (mes: string) => {
  TMessage({
    message: mes,
    type: 'default'
  })
}
